/*
 * Cursor.cpp
 *
 *  Created on: 4.2.2013
 *      Author: Travis
 */

#include "Cursor.h"
#include "../Map.h"

namespace RTSCursor
{

Cursor::Cursor(Map::Map *_map)
{
	Mode = MODE_PLAY;

	map = _map;

	LeftPressed = RightPressed = ctrl = build = false;

	editArea = new DataTypes::Cube(glm::vec3(0.0), 4.0);

	virtualEntity = NULL;

	// setup side bar
	sideBar = new Gadgets::Form(64, 500);
	sideBar->setBackground("sideBar.png");
	sideBar->setPos(
			glm::vec2(Engine::screenSettings.screenWidth - 64,
					Engine::screenSettings.screenHeight / 2 - 250));

	storeHouse = new Gadgets::Button(64, 64);
	storeHouse->setBackground("storeHouse_char.png");
	storeHouse->setPos(glm::vec2(0, 4));

	woodCutter = new Gadgets::Button(64, 64);
	woodCutter->setBackground("house_char.png");
	woodCutter->setPos(glm::vec2(0, 70));

	hunterHouse = new Gadgets::Button(64, 64);
	hunterHouse->setBackground("hunter_char.png");
	hunterHouse->setPos(glm::vec2(0, 134));

	bankHouse = new Gadgets::Button(64, 64);
	bankHouse->setBackground("bank_char.png");
	bankHouse->setPos(glm::vec2(0, 198));

	sideBar->addItem(storeHouse);
	sideBar->addItem(woodCutter);
	sideBar->addItem(hunterHouse);
	sideBar->addItem(bankHouse);
	//------------------
}

Cursor::~Cursor()
{
	delete (sideBar);
	delete (storeHouse);
	delete (woodCutter);
}

// convert 2D on screen to position in 3D space
void Cursor::updateOGLPos(int x, int y, int type)
{
	glm::vec3 buff;
	GLfloat depth;

	glm::mat4 ViewMatrix = World::world->getView();
	glm::mat4 Projection = World::world->getProjection();

	glReadPixels(x, Engine::screenSettings.screenHeight - y - 1, 1, 1,
			GL_DEPTH_COMPONENT, GL_FLOAT, &depth);

	glm::vec3 wincoord = glm::vec3(x, Engine::screenSettings.screenHeight - y - 1,
			depth);

	//gluUnProject( winX, winY, winZ, mvp, projection , viewport, &posX, &posY, &posZ);

	buff = glm::unProject(wincoord, ViewMatrix, Projection,
			glm::vec4(0.0f, 0.0f, (float) Engine::screenSettings.screenWidth,
					(float) Engine::screenSettings.screenHeight));

	if (type == UPDATE_ENT_CUR)
		OGLcursor = buff;
	else
		OGLcursorTer = buff;
}

void Cursor::selectAll()
{
	GameLogic::setVisibleUnitBar(true);

	for (unsigned int i = 0; i < map->getEntities()->getMovingCount(); i++)
	{
		Entity* eBuf = map->getEntities()->getMentity()[i];

		eBuf->setMarked(true);

		UnitMark.push_back(eBuf);
		GameLogic::insertUnitInBar(eBuf->getUnitBar());
	}
}

// called from thread in RTS!!!!
void Cursor::control(SDL_Event *event, float t)
{
	bool col = false;

	GameLogic::unitBar->control(event);
	// call control of sideBar
	sideBar->control(event);

	if (event->type == SDL_USEREVENT)
	{
		if (event->user.code == FORM_EVENT_MOUSE_CLICK_LEFT)
		{
			// calling from entitybutton
			if (event->user.data2 != NULL)
			{
				// retype to entity
				Entity *obj = static_cast<Entity*>(event->user.data2);

				// building ?
				if (obj->getParentType() == OBJ_BUILDING)
				{
					Building *objBuilding = static_cast<Building*>(event->user.data2);

					// is it add worker button???
					// and is there enough space in this building???
					if (objBuilding->getAddWorkerButton() == event->user.data1)
					{
						if (objBuilding->enoughSpace())
						{
							Villager* chck = NULL;

							if (objBuilding->getType() == OBJ_BBUILDER)
								chck = map->getEntities()->insertVillager(
										objBuilding->getGPoint(), 0.0, "Builder", "archer",
										OBJ_BUILDER, STATUS_READY);

							else if (objBuilding->getType() == OBJ_BLUMBERJACK)
								chck = map->getEntities()->insertVillager(
										objBuilding->getGPoint(), 0.0, "Lumberjack", "gatherer",
										OBJ_GATHERER, 4); // TODO CHANGE STATUS !!!!!!

							else if (objBuilding->getType() == OBJ_BHUNTER)
								chck = map->getEntities()->insertVillager(
										objBuilding->getGPoint(), 0.0, "Hunter", "archer",
										OBJ_HUNTER, STATUS_READY);
							else if (objBuilding->getType() == OBJ_BBANK)
								chck = map->getEntities()->insertVillager(
										objBuilding->getGPoint(), 0.0, "Taxman", "archer",
										OBJ_TAXMAN, STATUS_READY);

							//Villager* chck = map->getEntities()->insertVillager(objBuilding->getGPoint(), 0.0, "Worker", "archer");
							if (chck != NULL)
							{
								objBuilding->insertSlave(chck);
								gCon::con->print("New worker: %i", chck);

								GameLogic::resource->DecGold(chck->getCostGold());
							}

						}
						else
							gCon::con->print("No space in this building!");
					}
				}
			}

			// inserting store house
			if (event->user.data1 == storeHouse)
			{
				if (virtualEntity != NULL)
					delete (virtualEntity);

				virtualEntity = new BBuilder(OGLcursorTer, 0.0, "Store House",
						"storeHouse", map->getPool(), NULL);
				virtualEntity->setAge(100.0);

				build = true;
			}
			if (event->user.data1 == bankHouse)
			{
				if (virtualEntity != NULL)
					delete (virtualEntity);

				virtualEntity = new BBank(OGLcursorTer, 0.0, "City bank", "bank",
						map->getPool(), NULL);
				virtualEntity->setAge(100.0);

				build = true;
			}
			// inserting wood cutter house
			else if (event->user.data1 == woodCutter)
			{
				if (virtualEntity != NULL)
					delete (virtualEntity);

				virtualEntity = new BLumberjack(OGLcursorTer, 0.0, "Lumberjack",
						"house", map->getPool(), NULL);
				virtualEntity->setAge(100.0);

				build = true;
			} // inserting hunter house
			else if (event->user.data1 == hunterHouse)
			{
				if (virtualEntity != NULL)
					delete (virtualEntity);

				virtualEntity = new BHunter(OGLcursorTer, 0.0, "Hunter", "hunter",
						map->getPool(), NULL);
				virtualEntity->setAge(100.0);

				build = true;
			}
		}
	}
	else if (event->type == SDL_KEYDOWN)
	{
		if (event->key.keysym.sym == SDLK_LCTRL)
		{
			ctrl = true;
		}
		else if ((event->key.keysym.sym == SDLK_LEFT) && (virtualEntity != NULL))
		{
			virtualEntity->setR(virtualEntity->getR() + 5.0);
		}
		else if ((event->key.keysym.sym == SDLK_RIGHT) && (virtualEntity != NULL))
		{
			virtualEntity->setR(virtualEntity->getR() - 5.0);
		}
		else if (event->key.keysym.sym == SDLK_a)
		{
			selectAll();
		}

	}
	else if (event->type == SDL_KEYUP)
	{
		if (event->key.keysym.sym == SDLK_LCTRL)
		{
			ctrl = false;
		}
	}
	// mouse button click
	else if (event->type == SDL_MOUSEBUTTONDOWN)
	{
		// left mouse button click only if mouse is outside unitbar
		if ((event->button.button == (SDL_BUTTON_LEFT))
				&& (!GameLogic::unitBar->getMouseInside()))
		{
			// play mode
			if ((Mode == MODE_PLAY) && (!build))
			{
				col = false;

				for (unsigned int i = 0; i < map->getEntities()->getEntityCount(); i++)
				{
					if ((map->getEntities()->getEntity()[i]->pointInEntity(OGLcursor))
							&& (map->getEntities()->getEntity()[i]->getType() != OBJ_GRASS))
					{
						gCon::con->print("Marked unit status: %s",
								map->getEntities()->getEntity()[i]->getStringStatus().c_str());

						if ((UnitMark.size() > 0) && (!ctrl))
						{
							freeAllMarked();
							GameLogic::deleteItemsUnitBar();
							GameLogic::setVisibleUnitBar(false);
						}

						map->getEntities()->getEntity()[i]->setMarked(true);
						GameLogic::setVisibleUnitBar(true);
						UnitMark.push_back(map->getEntities()->getEntity()[i]);
						GameLogic::insertUnitInBar(
								map->getEntities()->getEntity()[i]->getUnitBar());

						col = true;

					}
				}

				if ((!col) && (UnitMark.size() > 0))
				{
					freeAllMarked();
					GameLogic::deleteItemsUnitBar();
					GameLogic::setVisibleUnitBar(false);
					gCon::con->print("Nothing marked.");
				}

			}
			// edit mode
			if (Mode == MODE_EDIT)
				LeftPressed = true;

			// build house
			if (build)
			{
				// try to build house
				if (GameLogic::resource->getWood() >= virtualEntity->getCost())
				{
					//check if building position is free
					PathFinder *pathinder = map->getPathfinder();

					if (pathinder->CheckBuildingPosition(virtualEntity->getBBox(),
							virtualEntity->get2dPosition()))
					{
						// create new entity with status PLACED
						map->getEntities()->insertBuilding(OGLcursorTer,
								virtualEntity->getR(), virtualEntity->getName(),
								virtualEntity->getModelFName(), 0.0, virtualEntity->getType(),
								STATUS_PLACED);

						gCon::con->print("Build new house on pos: x: %f y: %f, z: %f",
								OGLcursorTer.x, OGLcursorTer.y, OGLcursorTer.z);

						GameLogic::resource->DecWood(virtualEntity->getCost());
					}
				}
				else
					gCon::con->print("Not enough wood!!!");

				build = false;
			}

		}

		// right button click
		if (event->button.button == (SDL_BUTTON_RIGHT))
		{
			if (Mode == MODE_PLAY)
			{
				if (UnitMark.size() > 0)
				{
					goToAllMarked();
					gCon::con->print("Marked unit: I'm on the way");
				}

				build = false;
			}

			if (Mode == MODE_EDIT)
				RightPressed = true;
		}

	}
	else if (event->type == SDL_MOUSEBUTTONUP)
	{
		// left mouse button click
		if (event->button.button == (SDL_BUTTON_LEFT))
			LeftPressed = false;

		if (event->button.button == (SDL_BUTTON_RIGHT))
			RightPressed = false;
	}

	if (((LeftPressed) || (RightPressed)) && (Mode == MODE_EDIT))
	{
		int x = (int) OGLcursorTer.x;
		int y = (int) OGLcursorTer.z;

		float change = 0.05;

		if (RightPressed)
			change = -change;

		float yval = map->getTer()->get_value(x, y);

		map->getTer()->setPoint(x, y, yval + change);
		map->getTer()->setPoint(x - 1, y - 1, yval + change / 2);
		map->getTer()->setPoint(x - 1, y, yval + change / 2);
		map->getTer()->setPoint(x - 1, y + 1, yval + change / 2);
		map->getTer()->setPoint(x, y - 1, yval + change / 2);
		map->getTer()->setPoint(x + 1, y + 1, yval + change / 2);
		map->getTer()->setPoint(x + 1, y, yval + change / 2);
		map->getTer()->setPoint(x + 1, y - 1, yval + change / 2);
		map->getTer()->setPoint(x, y + 1, yval + change / 2);

		//map->getTer()->calcNormals(0,0,map->getTer()->get_size()-1);

		// move to save section
		//map->getOctree()->updateLocal(*editArea);
	}
}
//----------------------------------------------------------------------------

void Cursor::freeAllMarked()
{
	for (unsigned int i = 0; i < UnitMark.size(); i++)
		UnitMark[i]->setMarked(false);

	UnitMark.clear();
	ctrl = false;
}

void Cursor::goToAllMarked()
{
	for (unsigned int i = 0; i < UnitMark.size(); i++)
		UnitMark[i]->goTo(glm::vec2(OGLcursor.x, OGLcursor.z));
}

void Cursor::draw()
{
	if (Mode == MODE_EDIT)
	{
		editArea = new (editArea) DataTypes::Cube(OGLcursorTer, 4.0);

		editArea->drawCube(glm::vec3(0.0), 0.0, glm::vec3(0.0, 0.0, 1.0));
	}

	if (build)
	{
		virtualEntity->setPos(OGLcursorTer);

		virtualEntity->draw(SHADER_VIRTUAL);
	}

	sideBar->draw();
}

int Cursor::getMode() const
{
	return Mode;
}

void Cursor::setMode(int mode)
{
	Mode = mode;
}

const glm::vec3& Cursor::getOgLcursor() const
{
	return OGLcursor;
}

void Cursor::setOgLcursor(const glm::vec3& ogLcursor)
{
	OGLcursor = ogLcursor;
}

const std::vector<Entity*>& Cursor::getUnitMark() const
{
	return UnitMark;
}

void Cursor::setUnitMark(const std::vector<Entity*>& unitMark)
{
	UnitMark = unitMark;
}

}
